import boto3
import os
import logging
from typing import Dict, Any
from botocore.exceptions import ClientError, NoCredentialsError

logger = logging.getLogger(__name__)


class OSSS3Handler:
    """OSS S3-compatible storage handler"""

    def __init__(self, oss_config):
        self.bucket_name = oss_config['bucket']
        self.client = self._create_client(oss_config)

    def _create_client(self, oss_config):
        """Create S3 client"""
        try:
            return boto3.client(
                's3',
                aws_access_key_id=oss_config['access_key'],
                aws_secret_access_key=oss_config['secret_key'],
                endpoint_url=f"http://{oss_config['endpoint']}",
                # region_name='us-east-1'
            )
        except Exception as e:
            logger.error(f"Failed to create S3 client: {e}")

    def upload_file(self, local_file_path: str, object_key: str) -> Dict[str, Any]:
        """Upload file to OSS"""
        result = {"success": False, "object_key": object_key, "error": None}
        try:
            if not os.path.exists(local_file_path):
                raise FileNotFoundError(f"Local file not found: {local_file_path}")

            # Upload file
            self.client.upload_file(local_file_path, self.bucket_name, object_key)
            result["success"] = True
            logger.info(f"Successfully uploaded {local_file_path} to {object_key}")
        except FileNotFoundError as e:
            result["error"] = str(e)
            logger.error(f"File not found: {e}")
        except NoCredentialsError:
            result["error"] = "AWS credentials not found"
            logger.error("AWS credentials not found")
        except ClientError as e:
            result["error"] = f"AWS client error: {e}"
            logger.error(f"Failed to upload file: {e}")
        except Exception as e:
            result["error"] = f"Unexpected error: {e}"
            logger.error(f"Unexpected error during upload: {e}")
        return result

    def download_file(self, object_key: str, local_file_path: str) -> Dict[str, Any]:
        """Download file from OSS"""
        result = {"success": False, "object_key": object_key, "local_path": local_file_path, "error": None}

        try:
            # Ensure local directory exists
            local_dir = os.path.dirname(local_file_path)
            if local_dir and not os.path.exists(local_dir):
                os.makedirs(local_dir, exist_ok=True)

            # Download file
            self.client.download_file(self.bucket_name, object_key, local_file_path)
            result["success"] = True
            logger.info(f"Successfully downloaded {object_key} to {local_file_path}")
        except ClientError as e:
            error_code = e.response['Error']['Code']
            if error_code == 'NoSuchKey':
                result["error"] = f"Object not found: {object_key}"
            else:
                result["error"] = f"AWS client error: {e}"
            logger.error(f"Failed to download file: {e}")
        except Exception as e:
            result["error"] = f"Unexpected error: {e}"
            logger.error(f"Unexpected error during download: {e}")
        return result

    def list_objects(self, prefix: str = "") -> Dict[str, Any]:
        """
        List OSS objects
        :param prefix: Optional prefix to filter objects
        :return: Dict containing success status, list of objects, count, and error message if any
        """
        result = {"success": False, "objects": [], "count": 0, "error": None}

        try:
            response = self.client.list_objects_v2(Bucket=self.bucket_name, Prefix=prefix)
            objects = []
            if 'Contents' in response:
                for obj in response['Contents']:
                    objects.append({
                        "key": obj['Key'],
                        "size": obj['Size'],
                        "last_modified": obj['LastModified'].isoformat()
                    })
            result.update({"success": True, "objects": objects, "count": len(objects)})
            logger.info(f"Listed {len(objects)} objects with prefix: {prefix}")
        except ClientError as e:
            result["error"] = f"AWS client error: {e}"
            logger.error(f"Failed to list objects: {e}")
        except Exception as e:
            result["error"] = f"Unexpected error: {e}"
            logger.error(f"Unexpected error during list: {e}")
        return result

    def delete_object(self, object_key: str) -> Dict[str, Any]:
        """Delete OSS object"""
        result = {"success": False, "object_key": object_key, "error": None}

        try:
            self.client.delete_object(Bucket=self.bucket_name, Key=object_key)
            result["success"] = True
            logger.info(f"Successfully deleted object: {object_key}")
        except ClientError as e:
            result["error"] = f"AWS client error: {e}"
            logger.error(f"Failed to delete object: {e}")
        except Exception as e:
            result["error"] = f"Unexpected error: {e}"
            logger.error(f"Unexpected error during delete: {e}")
        return result
